/*
 * 描          述:  <描述>
 * 修  改   人:  PengQingyang
 * 修改时间:  2012-12-9
 * <修改描述:>
 */
package com.tx.component.generator.genmodel.impl;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;

import com.tx.component.generator.genmodel.SqlMapGenModel;
import com.tx.component.generator.util.EntityProperty;
import com.tx.component.generator.util.JPAGeneratorUtils;
import com.tx.component.generator.util.JPAGeneratorUtils.EntityPropertyJPAImpl;
import com.tx.core.exceptions.util.AssertUtils;
import com.tx.core.util.JPAParseUtils;

/**
 * 对应sqlMap顶层相关配置
 * <功能详细描述>
 * 
 * @author  PengQingyang
 * @version  [版本号, 2012-12-9]
 * @see  [相关类/方法]
 * @since  [产品/模块版本]
 */
public class JPASqlMapGeneratorModel implements SqlMapGenModel {
    
    /** 实体类型name */
    private final String entityTypeName;
    
    /** 实体类型simpleName */
    private final String entityTypeSimpleName;
    
    /** 表名 */
    private final String tableName;
    
    /** 表名缩写 */
    private final String simpleTableName;
    
    /** jpa字段列表 */
    private final List<EntityProperty> propertyList;
    
    /** 主键字段列表 */
    private final EntityProperty pkProperty;
    
    /** 是否有编码属性 */
    private EntityProperty createDateProperty;
    
    /** 是否有编码属性 */
    private EntityProperty codeProperty;
    
    /** 是否有是否有效的属性 */
    private EntityProperty validProperty;
    
    /** 父节点id对应的属性 */
    private EntityProperty parentIdProperty;
    
    /** 父节点id对应的属性 */
    private EntityProperty parentProperty;
    
    /** 排序字段 */
    private String defaultOrderBy;
    
    /** <默认构造函数> */
    public JPASqlMapGeneratorModel(Class<?> entityType) {
        super();
        //this.entityType = entityType;
        this.entityTypeName = entityType.getName();
        this.entityTypeSimpleName = entityType.getSimpleName();
        
        this.tableName = JPAParseUtils.parseTableName(entityType);
        this.simpleTableName = generateSimpleTableName(
                entityType.getSimpleName());
        
        List<EntityPropertyJPAImpl> jpaPropertyList = JPAGeneratorUtils
                .parseEntityPropertyList(entityType);
        this.propertyList = jpaPropertyList.stream().map(column -> {
            return column;
        }).collect(Collectors.toList());
        
        this.pkProperty = this.propertyList.stream().filter(column -> {
            return column.isPrimaryKey();
        }).collect(Collectors.toList()).get(0);
        AssertUtils.isTrue(this.pkProperty != null, "没有找到主键字段");
        
        jpaPropertyList.stream().forEach(property -> {
            if (StringUtils.equals("code", property.getPropertyName())
                    && !property.isPrimaryKey()) {
                //如果主键就是code，则无需标定hasCodeProperty
                this.codeProperty = property;
                AssertUtils.isTrue(
                        String.class.isAssignableFrom(
                                property.getJpaColumnInfo().getPropertyType()),
                        "code type should is String.");
            } else if (StringUtils.equals("valid",
                    property.getPropertyName())) {
                this.validProperty = property;
                AssertUtils.isTrue(Boolean.class.isAssignableFrom(
                        property.getJpaColumnInfo().getPropertyType())
                        || boolean.class.equals(
                                property.getJpaColumnInfo().getPropertyType()),
                        "valid type should is boolean or Boolean.");
            } else if (StringUtils.equals("createDate",
                    property.getPropertyName())) {
                this.createDateProperty = property;
                AssertUtils.isTrue(Date.class.isAssignableFrom(
                        property.getJpaColumnInfo().getPropertyType())
                        || java.sql.Date.class.isAssignableFrom(
                                property.getJpaColumnInfo().getPropertyType()),
                        "createDate type should is Date.");
            } else if (StringUtils.equals("parentId",
                    property.getPropertyName())) {
                this.parentIdProperty = property;
                AssertUtils.isTrue(
                        ((EntityPropertyJPAImpl) this.pkProperty)
                                .getJpaColumnInfo()
                                .getPropertyType()
                                .equals(property.getJpaColumnInfo()
                                        .getPropertyType()),
                        "parentId type:{} should equals pk type:{}.",
                        new Object[] {
                                property.getJpaColumnInfo().getPropertyType(),
                                ((EntityPropertyJPAImpl) this.pkProperty)
                                        .getJpaColumnInfo()
                                        .getPropertyType() });
            } else if (StringUtils.equals("parent",
                    property.getPropertyName())) {
                this.parentProperty = property;
                AssertUtils.isTrue(
                        property.getJpaColumnInfo()
                                .getPropertyType()
                                .equals(entityType),
                        "parent type:{} should equals entity type:{}.",
                        new Object[] {
                                property.getJpaColumnInfo().getPropertyType(),
                                entityType });
            }
        });
        
        this.defaultOrderBy = JPAParseUtils.parseOrderBy(entityType,
                jpaPropertyList.stream()
                        .map(t -> t.getJpaColumnInfo())
                        .collect(Collectors.toList()),
                "createDate",
                "id",
                "code",
                "name");
    }
    
    /**
     * @return
     */
    @Override
    public String getEntityTypeName() {
        return entityTypeName;
    }
    
    /**
     * @return
     */
    @Override
    public String getEntityTypeSimpleName() {
        return entityTypeSimpleName;
    }
    
    /**
     * @return
     */
    @Override
    public String getTableName() {
        return tableName;
    }
    
    /**
     * @return
     */
    @Override
    public String getSimpleTableName() {
        return simpleTableName;
    }
    
    /**
     * @return
     */
    @Override
    public List<EntityProperty> getPropertyList() {
        return this.propertyList;
    }
    
    /**
     * @return
     */
    @Override
    public EntityProperty getCodeProperty() {
        return this.codeProperty;
    }
    
    /**
     * @return
     */
    @Override
    public EntityProperty getValidProperty() {
        return this.validProperty;
    }
    
    /**
     * @return
     */
    @Override
    public EntityProperty getPkProperty() {
        return this.pkProperty;
    }
    
    /**
     * @return
     */
    @Override
    public EntityProperty getCreateDateProperty() {
        return this.createDateProperty;
    }
    
    /**
     * @return
     */
    @Override
    public String getDefaultOrderBy() {
        return this.defaultOrderBy;
    }
    
    /**
     * @return
     */
    @Override
    public EntityProperty getParentIdProperty() {
        return this.parentIdProperty;
    }
    
    /**
     * @return
     */
    @Override
    public EntityProperty getParentProperty() {
        return this.parentProperty;
    }
    
    /**
     * 生成表名缩写<br/>
     * <功能详细描述>
     * @param entitySimpleName
     * @return [参数说明]
     * 
     * @return String [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    private static String generateSimpleTableName(String entityTypeSimpleName) {
        //取字段名数组中最后一个字符串
        String nameArraySource = entityTypeSimpleName;
        nameArraySource = nameArraySource.replaceAll("[A-Z]", ",$0");
        nameArraySource = nameArraySource.replaceAll("_", ",");
        String[] nameArray = StringUtils.splitByWholeSeparator(nameArraySource,
                ",");
        StringBuilder sb = new StringBuilder();
        for (String columnTemp : nameArray) {
            if (StringUtils.isEmpty(columnTemp)) {
                continue;
            }
            sb.append(columnTemp.charAt(0));
        }
        String simpleTableName = sb.toString().toUpperCase();
        if (StringUtils.equalsAnyIgnoreCase("or", simpleTableName)) {
            simpleTableName = "O";
        }
        if (StringUtils.equalsAnyIgnoreCase("and", simpleTableName)) {
            simpleTableName = "A";
        }
        if (StringUtils.equalsAnyIgnoreCase("is", simpleTableName)) {
            simpleTableName = "I";
        }
        if (StringUtils.equalsAnyIgnoreCase("NULL", simpleTableName)) {
            simpleTableName = "N";
        }
        if (StringUtils.equalsAnyIgnoreCase("exists", simpleTableName)) {
            simpleTableName = "E";
        }
        if (StringUtils.equalsAnyIgnoreCase("not", simpleTableName)) {
            simpleTableName = "N";
        }
        if (StringUtils.equalsAnyIgnoreCase("in", simpleTableName)) {
            simpleTableName = "I";
        }
        return simpleTableName;
    }
}
